#pragma once


#include <compl.h>

#include <dbg.h>



#include <stdlib.h>
#ifndef __USE_GNU
	#define __USE_GNU
#endif
#include <pthread.h>
#include <sched.h>
SAI int pthread_create_wrapper(pthread_t *newthread, pthread_attr_t *attr, void *(*start_routine)(void *), void *args)
{
	return pthread_create(newthread, attr, start_routine, args);
}
#define __MAP_CLR(core_id)	__CPU_CLR_S(core_id, sizeof(cpu_set_t), &__mycpuset)
#define __EXCLUDE_CORE(...)	{cpu_set_t __mycpuset; __memset(&__mycpuset, 0xff, sizeof(cpu_set_t)); MAPS(__MAP_CLR, __VA_ARGS__); try_commit_aff(&__mycpuset); }

#define EXCLUDE_CORE(...)	\
do{ cpu_set_t __mycpuset;	\
	if (sched_getaffinity(pthread_self(), sizeof(__mycpuset), &__mycpuset) == 0) {  \
		MAPS(__MAP_CLR, __VA_ARGS__); \
		while (0 != try_commit_aff(&__mycpuset)){ \
			/* printf("failed to exclude core to %s\n", #__VA_ARGS__); */ \
		}\
	}\
}while(0)

#define __MAP_SET(core_id)		__CPU_SET_S((core_id), sizeof(cpu_set_t), &__mycpuset)
#define BIND_CORE(...)		do{\
	cpu_set_t __mycpuset; __memset(&__mycpuset, 0, sizeof(cpu_set_t)); \
	MAPS(__MAP_SET, __VA_ARGS__); \
	while (0 != try_commit_aff(&__mycpuset)){\
		/* printf("failed to bind core to %lx\n", *((word_t *)&__mycpuset)); */ \
		/* PAUSE(); */\
	}\
	/* printf("bind core to %s\n", #__VA_ARGS__); */\
	}while(0)
#define CLR_BIND()	do{\
	cpu_set_t __mycpuset; __memset(&__mycpuset, 0xff, sizeof(cpu_set_t)); \
	while (0 != try_commit_aff(&__mycpuset)){\
		/* PAUSE(); */\
	}\
	}while(0)
SAI int  try_commit_aff(cpu_set_t *cpuset){
	return pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), cpuset);
}

SAI int is_core_active(hword_t core_id)
{
	cpu_set_t get;
	__CPU_ZERO_S(sizeof(get), &get);
	if (sched_getaffinity(0, sizeof(get), &get) == -1) //获取线程CPU亲和力
	{
		// printf("warning: cound not get thread affinity, continuing...\n");
	}
	if (__CPU_ISSET_S(core_id, sizeof(get), &get)) //判断线程与哪个CPU有亲和力
	{
		return 1;
	}
	return 0;
}

SAI void display_cpu_affinity(cid_t bind_core)
{
	PARAM_USED(bind_core)
	cpu_set_t get;
	__CPU_ZERO_S(sizeof(get), &get);
	if (sched_getaffinity(0, sizeof(get), &get) == -1) //获取线程CPU亲和力
	{
		// printf("warning: could not get thread affinity, continuing...\n");
	}
	for (unsigned long i = 0; i < sizeof(get) * __CHAR_BIT__; i++)
	{
		if (__CPU_ISSET_S(i, sizeof(get), &get)) //判断线程与哪个CPU有亲和力
		{
			// #ifndef NO_BIND
			//			 if (bind_core != i)
			//				 fprintf(stderr, "this thread %d is running another processor : %d\n", bind_core, i);
			// #endif
		}
	}
	// struct sched_param param;
	// int policy;
	// if(!pthread_getschedparam(pthread_self(),&policy,&param)){
	//	 printf("scheduling policy %d, pr :%d\n",policy, param.sched_priority);
	// }
}

SAI void __display_cpu_affinity(cid_t bind_core)
{
	PARAM_USED(bind_core)
	cpu_set_t get;
	__CPU_ZERO_S(sizeof(get), &get);
	if (sched_getaffinity(0, sizeof(get), &get) == -1) //获取线程CPU亲和力
	{
		// printf("warning: could not get thread affinity, continuing...\n");
	}
	for (unsigned long i = 0; i < sizeof(get) * __CHAR_BIT__; i++)
	{
		if (__CPU_ISSET_S(i, sizeof(get), &get)) //判断线程与哪个CPU有亲和力
		{
			// #ifndef NO_BIND
			// if (bind_core != i)
			//	 fprintf(stderr, "this thread %d is running another processor : %d\n", bind_core, i);
			// #endif
		}
	}
	// struct sched_param param;
	// int policy;
	// if(!pthread_getschedparam(pthread_self(),&policy,&param)){
	//	 printf("scheduling policy %d, pr :%d\n",policy, param.sched_priority);
	// }
}

static struct sched_param param;
static pthread_attr_t attr;
// #define USE_FIFO

typedef void *(*tfunc_t)(void *);
typedef struct
{
	tfunc_t func;
	word_t core_id;
} pargs_t;


SAI pthread_t __create_thread_bindcore(hword_t core_id, tfunc_t function)
{

	cpu_set_t mask;
	pthread_t ret;
	__CPU_ZERO_S(sizeof(cpu_set_t), &mask);
	__CPU_SET_S(core_id, sizeof(cpu_set_t), &mask);
	pargs_t *tmp = (pargs_t *)malloc(sizeof(pargs_t));
	pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
	tmp->core_id = core_id;
	tmp->func = function;
	if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED))
	{
		dbg_printf("pthread_attr_setinheritsched error \n");
		return -1;
	}

#ifdef USE_FIFOSCHED
	if (pthread_attr_setschedpolicy(attr, SCHED_FIFO) != 0)
	{
		dbg_printf("pthread_attr_setschedpolicy set SCHED_FIFO failed\n");
		return -1;
	}
	param.sched_priority = sched_get_priority_max(SCHED_FIFO);
#else
	param.sched_priority = sched_get_priority_max(SCHED_OTHER);
	if (pthread_attr_setschedparam(&attr, &param) != 0)
	{
		dbg_printf("set prio %d failed\n", param.sched_priority);
	}
	// cac_printf( "prio %d\n", param.sched_priority);
#endif

	if (pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &mask))
	{
		dbg_printf("pthread_attr_setaffinity error\n");
		return -1;
	}
	cmb();
	if (pthread_create(&ret, &attr, function, (void *)tmp) != 0)
	{
		dbg_printf("can't create thread at core %d\n", core_id);
		return -1;
	}
	return ret;
}
